package com.learning.thread.base.sync;

/**
 * ClassName: SynchronizedThreadSafe
 * Description: 使用 Synchronized 实现线程安全：线程互斥
 * 1. 代码简洁，线程安全，性能靠谱，自动回收
 * 2. 锁对象、锁代码块、锁class类三种用法
 * 3. 只能保证线程安全，无法控制复杂逻辑的多线程交互，如需实现多线程交互，需要配合使用Object对象的`wait`、`notify` 方法
 * <p>
 * Date: 2018/6/28 17:26 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class SynchronizedThreadSafe {


    public static void main(String[] args) {
        // 锁定对象，必须是同一个对象
        DataObject object = new DataObject();
        new Thread(new InThread(object), "thead 0 ").start();
        new Thread(new InThread(object), "thead 1 ").start();

        // 不同的对象, 锁对象失效。锁类就无所谓
        DataObject object2 = new DataObject();
        new Thread(new InThread(object2), "thead 2 ").start();
    }

    /**
     * 线程对象
     */
    static class InThread implements Runnable {

        private DataObject data;

        public InThread(DataObject data) {
            this.data = data;
        }

        @Override
        public void run() {
            data.get("abcdefghijklmnopqrztuvwzyz");
        }
    }

    /**
     * 业务数据对象
     */
    static class DataObject {

        /**
         * 线程安全
         * 测试结果：不规则
         * thead 1 :  thead 0 :  abcdefghijklmnopqrztuvwzyzabcdefghi
         * jklmnopqrztuvwzyz
         *
         * @param name
         */
        private void getOutLock(String name) {
            int len = name.length();
            System.out.print(Thread.currentThread().getName() + ":  ");
            for (int i = 0; i < len; i++) {
                System.out.print(name.charAt(i));
            }
            System.out.println();
        }


        /**
         * 锁对象：锁定非静态方法
         *
         * @param name
         */
        private synchronized void get(String name) {
            int len = name.length();
            System.out.print(Thread.currentThread().getName() + ":  ");
            for (int i = 0; i < len; i++) {
                System.out.print(name.charAt(i));
            }
            System.out.println();
        }


        /**
         * 锁对象：直接锁定对象: synchronized (this)
         * 注意：锁定同一个对象
         *
         * @param name
         */
        private void get2(String name) {
            int len = name.length();
            synchronized (this) {
                System.out.print(Thread.currentThread().getName() + ":  ");
                for (int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            }
        }

        /**
         * 锁对象: 锁定最小代码块
         *
         * @param name
         */
        private void get3(String name) {
            int len = name.length();
            synchronized (name) {
                System.out.print(Thread.currentThread().getName() + ":  ");
                for (int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            }
        }


        /**
         * 锁类：直接锁Class类
         *
         * @param name
         */
        public static void get4(String name) {
            int len = name.length();
            synchronized (DataObject.class) {
                System.out.print(Thread.currentThread().getName() + ":  ");
                for (int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            }
        }

        /**
         * 锁类：锁静态方法，锁定字节码
         *
         * @param name
         */
        public synchronized static void get5(String name) {
            int len = name.length();
            System.out.print(Thread.currentThread().getName() + ":  ");
            for (int i = 0; i < len; i++) {
                System.out.print(name.charAt(i));
            }
            System.out.println();

        }

    }
}
